﻿////////////////////////////////////////////////////////////////////////////
//
//  Immense Engine Source File.
//  Copyright (C), Indloon 2012
// -------------------------------------------------------------------------
//  File name:   ieMathVector2.h
//  Description: ieMath vector 2D
//  Created:     8/12/2012 Genert Org
//  Compilers:   Visual C++ 2010 Express
// -------------------------------------------------------------------------
//  History:
//
////////////////////////////////////////////////////////////////////////////
#ifndef __IMMENSEENGINE_MATH_VECTOR2D_H
#define __IMMENSEENGINE_MATH_VECTOR2D_H
#pragma once

/*  1. C L A S S
	=========================================================================== */

class ieVec2 {
public:
    float x;
    float y;
                    ieVec2 ( void );
    explicit        ieVec2( const float value );
    explicit        ieVec2( const float x, const float y );
	
    float	        operator [] ( const int index ) const;
    float &	        operator [] ( const int index );
    ieVec2 &        operator = ( const ieVec2 &vec );
    bool            operator == ( const ieVec2 &vec ) const;
    bool            operator != ( const ieVec2 &vec ) const;
    ieVec2          operator - () const;
    ieVec2          operator + ( const ieVec2 &vec ) const;
    ieVec2          operator - ( const ieVec2 &vec ) const;
    ieVec2          operator * ( const ieVec2 &vec ) const;
    ieVec2          operator / ( const ieVec2 &vec ) const;
    ieVec2          operator + ( const float value ) const;
    ieVec2          operator - ( const float value ) const;
    ieVec2          operator * ( const float value ) const;
    ieVec2          operator / ( const float value ) const;
    ieVec2 &	    operator += ( const ieVec2 &vec );
    ieVec2 &	    operator -= ( const ieVec2 &vec );
    ieVec2 &	    operator *= ( const ieVec2 &vec );
    ieVec2 &	    operator /= ( const ieVec2 &vec );
    ieVec2 &	    operator += ( const float value );
    ieVec2 &	    operator -= ( const float value );
    ieVec2 &	    operator *= ( const float value );
    ieVec2 &	    operator /= ( const float value );
    bool            operator < ( const ieVec2 &vec ) const;
    bool            operator > ( const ieVec2 &vec ) const;
	
    void            Set( const float value );
    void            Set( const float x, const float y );
    void            Clear( void );
    void            Zero( void );
    bool            IsCleared( void ) const;
    bool            IsZero( void ) const;

    bool            AreEqual( const ieVec2 &vec ) const;
    bool            AreEqual( const ieVec2 &vec, float epsilon ) const;
    float           Length( void ) const;
    float	        LengthFast( void ) const;
    float	        LengthSqr( void ) const;
    float           Normalize( void );
    void            NormalizeFast( void );
    void            Snap( void );
    void	        Truncate( void );
    void	        Clamp( const ieVec2 &min, const ieVec2 &max );
    void	        Clamp( const float min, const float max );
    void	        Average( const ieVec2 &vec1, const ieVec2 &ieVec2 );
    float	        Dot( const ieVec2 &vec) const;
    void	        Lerp( const ieVec2 &from, const ieVec2 &to, const float frac );
    void	        LerpFast( const ieVec2 &from, const ieVec2 &to, const float frac );
    float	        Distance( const ieVec2 &vec ) const;
    float	        DistanceFast( const ieVec2 &vec ) const;
    float	        DistanceSqr( const ieVec2 &vec ) const;
};


/*  2. F U N C T I O N S
	=========================================================================== */
	
// -------------------------------------------------------------------------------------------------------------
ILINE ieVec2::ieVec2( void )
{
    // ...
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieVec2::ieVec2( const float value )
{
    this->x = value;
    this->y = value;
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieVec2::ieVec2( const float x, const float y )
{
    this->x = x;
    this->y = y;
}
// -------------------------------------------------------------------------------------------------------------
ILINE float ieVec2::operator[] ( const int index ) const
{
    return ( &x )[index];
}
// -------------------------------------------------------------------------------------------------------------
ILINE float &ieVec2::operator[] ( const int index )
{
    return ( &x )[index];
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieVec2 &ieVec2::operator = ( const ieVec2 &vec ) 
{
    x = vec.x;
    y = vec.y;
	
    return *this;
}
// -------------------------------------------------------------------------------------------------------------
ILINE bool ieVec2::operator == ( const ieVec2 &vec ) const 
{
    if( ( x != vec.x ) || ( y != vec.y ) )
    {
        return false;
    } 
    else 
    {
        return true;
    }
}
// -------------------------------------------------------------------------------------------------------------
ILINE bool ieVec2::operator != ( const ieVec2 &vec ) const 
{
    if( ( x == vec.x ) && ( y == vec.y ) )
    {
        return false;
    } 
    else 
    {
        return true;
    }
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieVec2 ieVec2::operator - () const 
{
    return ieVec2( -x, -y );
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieVec2 ieVec2::operator + ( const ieVec2 &vec ) const 
{
    return ieVec2( x + vec.x, y + vec.y );
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieVec2 ieVec2::operator - ( const ieVec2 &vec ) const 
{
    return ieVec2( x - vec.x, y - vec.y );
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieVec2 ieVec2::operator * ( const ieVec2 &vec ) const 
{
    return ieVec2( x * vec.x, y * vec.y );
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieVec2 ieVec2::operator / ( const ieVec2 &vec ) const 
{
    return ieVec2( x / vec.x, y / vec.y );
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieVec2 ieVec2::operator + ( const float value ) const 
{
    return ieVec2( x + value, y + value );
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieVec2 ieVec2::operator - ( const float value ) const 
{
    return ieVec2( x - value, y - value );
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieVec2 ieVec2::operator * ( const float value ) const 
{
    return ieVec2( x * value, y * value );
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieVec2 ieVec2::operator / ( const float value ) const 
{
    float	scale = 1.0f / value;

    return ieVec2( x * scale, y * scale );
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieVec2 &ieVec2::operator += ( const ieVec2 &vec )
{
    x += vec.x;
    y += vec.y;

    return *this;
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieVec2 &ieVec2::operator -= ( const ieVec2 &vec )
{
    x -= vec.x;
    y -= vec.y;

    return *this;
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieVec2 &ieVec2::operator *= ( const ieVec2 &vec )
{
    x *= vec.x;
    y *= vec.y;

    return *this;
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieVec2 &ieVec2::operator /= ( const ieVec2 &vec )
{
    x /= vec.x;
    y /= vec.y;

    return *this;
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieVec2 &ieVec2::operator += ( const float value )
{
    x += value;
    y += value;

    return *this;
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieVec2 &ieVec2::operator -= ( const float value )
{
    x -= value;
    y -= value;

    return *this;
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieVec2 &ieVec2::operator *= ( const float value )
{
    x *= value;
    y *= value;

    return *this;
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieVec2 &ieVec2::operator /= ( const float value )
{
    float scale = 1.0f / value;

    x *= scale;
    y *= scale;

    return *this;
}
// -------------------------------------------------------------------------------------------------------------
ILINE bool ieVec2::operator < ( const ieVec2 &vec ) const
{
    if( ( ( x < vec.x ) && ( y < vec.y ) ) || ( ( x < vec.x ) || ( y < vec.y ) ) )
    {
        return true;
    } 
    else if( ( ( x > vec.x ) && ( y > vec.y ) ) || ( ( x > vec.x ) || ( y > vec.y ) ) )
    {
        return false;
    } 
    else 
    {
        return false;
    }
}
// -------------------------------------------------------------------------------------------------------------
ILINE bool ieVec2::operator > ( const ieVec2 &vec ) const
{
    if( ( ( x > vec.x ) && ( y > vec.y ) ) || ( ( x > vec.x ) || ( y > vec.y ) ) )
    {
        return true;
    }
    else if( ( ( x < vec.x ) && ( y < vec.y ) ) || ( ( x < vec.x ) || ( y < vec.y ) ) )
    {
        return false;
    }
    else
    {
        return false;
    }
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieVec2::Set( const float value )
{
    this->x = value;
    this->y = value;
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieVec2::Set( const float x, const float y )
{
    this->x = x;
    this->y = y;
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieVec2::Clear( void )
{
    x = y = 0.0f;
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieVec2::Zero( void )
{
    x = y = 0.0f;
}
// -------------------------------------------------------------------------------------------------------------
ILINE bool ieVec2::IsCleared( void ) const
{
    if( ( x != 0.0f ) || ( y != 0.0f ) )
    {
        return false;
    } 
    else
    {
        return true;
    }
}
// -------------------------------------------------------------------------------------------------------------
ILINE bool ieVec2::IsZero( void ) const
{
    if( ( x != 0.0f ) || ( y != 0.0f ) )
    {
        return false;
    } 
    else
    {
        return true;
    }
}
// -------------------------------------------------------------------------------------------------------------
ILINE bool ieVec2::AreEqual( const ieVec2 &vec ) const
{	
    if( ( x != vec.x ) && ( y != vec.y ) ) 
    {
        return false;
    }
    else
    {
        return true;
    }
}
// -------------------------------------------------------------------------------------------------------------
ILINE bool ieVec2::AreEqual( const ieVec2 &vec, float epsilon ) const
{
    return ( ( ieMath::Fabs( x - vec.x ) < epsilon ) && ( ieMath::Fabs( y - vec.y ) < epsilon ) );
}
// -------------------------------------------------------------------------------------------------------------
ILINE float ieVec2::Length( void ) const
{
    return ( ieMath::Sqrt( ( x * x ) + ( y * y ) ) );
}
// -------------------------------------------------------------------------------------------------------------
ILINE float ieVec2::LengthFast( void ) const 
{
    return ieMath::SqrtFast( ( x * x ) + ( y * y ) );
}
// -------------------------------------------------------------------------------------------------------------
ILINE float ieVec2::LengthSqr( void ) const 
{
    return ( ( x * x ) + ( y * y ) );
}
// -------------------------------------------------------------------------------------------------------------
ILINE float ieVec2::Normalize( void )
{
	float	length, invLength;

	length = ieMath::Sqrt(x*x + y*y);

	if ( length )
	{
		invLength = 1.0f / length;

		x *= invLength;
		y *= invLength;
	}

	return length;
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieVec2::NormalizeFast( void )
{
	float	invLength;

	invLength = ieMath::RSqrt( ( x*x ) + ( y*y ) );

	x *= invLength;
	y *= invLength;
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieVec2::Snap( void )
{
	x = ieMath::Round( x );
	y = ieMath::Round( y );
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieVec2::Truncate( void )
{
	x = ieMath::FloatToInt( x) ;
	y = ieMath::FloatToInt( y );
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieVec2::Clamp( const ieVec2 &min, const ieVec2 &max )
{
	x = ( x < min.x ) ? min.x : ( x > max.x ) ? max.x : x;
	y = ( y < min.y ) ? min.y : ( y > max.y ) ? max.y : y;
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieVec2::Clamp( const float min, const float max )
{
	x = ( x < min ) ? min : ( x > max ) ? max : x;
	y = ( y < min)  ? min : ( y > max ) ? max : y;
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieVec2::Average( const ieVec2 &vec1, const ieVec2 &ieVec2 )
{
	x = ( vec1.x + ieVec2.x ) * 0.5f;
	y = ( vec1.y + ieVec2.y ) * 0.5f;
}
// -------------------------------------------------------------------------------------------------------------
ILINE float ieVec2::Dot( const ieVec2 &vec ) const 
{
	return x * vec.x + y * vec.y;
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieVec2::Lerp( const ieVec2 &from, const ieVec2 &to, const float frac )
{
	if( frac <= 0.0f )
	{
		*this = from;
		return;
	}

	if( frac >= 1.0f )
	{
		*this = to;
		return;
	}

	x = from.x + ( to.x - from.x ) * frac;
	y = from.y + ( to.y - from.y ) * frac;
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieVec2::LerpFast( const ieVec2 &from, const ieVec2 &to, const float frac )
{
	x = from.x + ( to.x - from.x ) * frac;
	y = from.y + ( to.y - from.y ) * frac;
}
// -------------------------------------------------------------------------------------------------------------
ILINE float ieVec2::Distance( const ieVec2 &vec ) const 
{
	float xd, yd;

	xd = vec.x - x;
	yd = vec.y - y;

	return ieMath::Sqrt( ( xd * xd ) + ( yd * yd ) );
}
// -------------------------------------------------------------------------------------------------------------
ILINE float ieVec2::DistanceFast( const ieVec2 &vec ) const 
{
	float xd, yd;

	xd = vec.x - x;
	yd = vec.y - y;

    return ieMath::SqrtFast( ( xd * xd ) + ( yd * yd ) );
}
// -------------------------------------------------------------------------------------------------------------
ILINE float ieVec2::DistanceSqr( const ieVec2 &vec ) const 
{
	float xd, yd;

	xd = vec.x - x;
	yd = vec.y - y;

	return ( xd * xd ) + ( yd * yd );
}
// -------------------------------------------------------------------------------------------------------------


#endif // __IMMENSEENGINE_MATH_VECTOR2D_H